package org.gtugs.raffler.master;

import org.alljoyn.bus.BusAttachment;
import org.alljoyn.bus.BusListener;
import org.alljoyn.bus.Mutable;
import org.alljoyn.bus.SessionOpts;
import org.alljoyn.bus.SessionPortListener;
import org.alljoyn.bus.Status;
import org.gtugs.raffler.interfaces.RaffleMasterInterface;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

public class BusHandler extends Handler {
    
    private BusAttachment mBus;
    private RaffleService mRaffleService;

    
    public BusHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
        /* Connect to the bus and start our service. */
        case RaffleMasterInterface.CONNECT: { 
            /*
             * All communication through AllJoyn begins with a BusAttachment.
             *
             * A BusAttachment needs a name. The actual name is unimportant except for internal
             * security. As a default we use the class name as the name.
             *
             * By default AllJoyn does not allow communication between devices (i.e. bus to bus
             * communication).  The second argument must be set to Receive to allow
             * communication between devices.
             */ 
            mBus = new BusAttachment("org.gtugs.raffler.master", BusAttachment.RemoteMessage.Receive);
            
            /*
             * Create a bus listener class  
             */
            mBus.registerBusListener(new BusListener());
            
            /* 
             * To make a service available to other AllJoyn peers, first register a BusObject with
             * the BusAttachment at a specific path.
             *
             * Our service is the SimpleService BusObject at the "/SimpleService" path.
             */
            Status status = mBus.registerBusObject(mRaffleService, "/RaffleService");
            logStatus("BusAttachment.registerBusObject()", status);
            if (status != Status.OK) {
                return;
            }
            
            
            
            /*
             * The next step in making a service available to other AllJoyn peers is to connect the
             * BusAttachment to the bus with a well-known name.  
             */
            /*
             * connect the BusAttachement to the bus
             */
            status = mBus.connect();
            logStatus("BusAttachment.connect()", status);
            if (status != Status.OK) {
                return;
            }
            
            /*
             * Create a new session listening on the contact port of the chat service.
             */
            Mutable.ShortValue contactPort = new Mutable.ShortValue(RaffleMasterInterface.CONTACT_PORT);
            
            SessionOpts sessionOpts = new SessionOpts();
            sessionOpts.traffic = SessionOpts.TRAFFIC_MESSAGES;
            sessionOpts.isMultipoint = false;
            sessionOpts.proximity = SessionOpts.PROXIMITY_ANY;
            sessionOpts.transports = SessionOpts.TRANSPORT_ANY;

            status = mBus.bindSessionPort(contactPort, sessionOpts, new SessionPortListener() {
                @Override
                public boolean acceptSessionJoiner(short sessionPort, String joiner, SessionOpts sessionOpts) {
                    if (sessionPort == RaffleMasterInterface.CONTACT_PORT) {
                        return true;
                    } else {
                        return false;
                    }
                }
            });
            logStatus(String.format("BusAttachment.bindSessionPort(%d, %s)",
                      contactPort.value, sessionOpts.toString()), status);
            if (status != Status.OK) {
                return;
            }
            
            /*
             * request a well-known name from the bus
             */
            int flag = BusAttachment.ALLJOYN_REQUESTNAME_FLAG_REPLACE_EXISTING | BusAttachment.ALLJOYN_REQUESTNAME_FLAG_DO_NOT_QUEUE;
            
            status = mBus.requestName(RaffleMasterInterface.SERVICE_NAME, flag);
            logStatus(String.format("BusAttachment.requestName(%s, 0x%08x)", RaffleMasterInterface.SERVICE_NAME, flag), status);
            if (status == Status.OK) {
            	/*
            	 * If we successfully obtain a well-known name from the bus 
            	 * advertise the same well-known name
            	 */
            	status = mBus.advertiseName(RaffleMasterInterface.SERVICE_NAME, SessionOpts.TRANSPORT_ANY);
                logStatus(String.format("BusAttachement.advertiseName(%s)", RaffleMasterInterface.SERVICE_NAME), status);
                if (status != Status.OK) {
                	/*
                     * If we are unable to advertise the name, release
                     * the well-known name from the local bus.
                     */
                    status = mBus.releaseName(RaffleMasterInterface.SERVICE_NAME);
                    logStatus(String.format("BusAttachment.releaseName(%s)", RaffleMasterInterface.SERVICE_NAME), status);
                	return;
                }
            }
            
            break;
        }
        
        /* Release all resources acquired in connect. */
        case RaffleMasterInterface.DISCONNECT: {
            /* 
             * It is important to unregister the BusObject before disconnecting from the bus.
             * Failing to do so could result in a resource leak.
             */
            mBus.unregisterBusObject(mRaffleService);
            mBus.disconnect();
            this.getLooper().quit();
            break;   
        }

        default:
            break;
        }
    }
    
    private void logStatus(String msg, Status status) {
        String log = String.format("%s: %s", msg, status);
        if (status == Status.OK) {
            Log.i(ServiceActivity.TAG, log);
        } else {
            Log.e(ServiceActivity.TAG, log);
        }
    }
}
